package com.ksyun.ks3.services.handler;

import java.io.File;


import com.ksyun.ks3.exception.Ks3ClientException;
import com.ksyun.ks3.exception.Ks3ServiceException;
import com.ksyun.ks3.model.HttpHeaders;
import com.ksyun.ks3.model.ObjectMetadata;
import com.ksyun.ks3.model.result.GetObjectResult;
import com.ksyun.ks3.model.transfer.RequestProgressListener;
import com.ksyun.ks3.services.request.GetObjectRequest;
import com.ksyun.ks3.services.request.Ks3HttpRequest;
import com.ksyun.ks3.util.Md5Utils;
import com.ksyun.ks3.util.ResponseUtils;

import okhttp3.Headers;

public abstract class GetObjectResponseHandler extends FileAsyncHttpResponseHandler implements RequestProgressListener {

    private String mBucketName;
    private String mObjectKey;

    public GetObjectResponseHandler(File file, boolean append) {
        super(file, append);
    }

    public GetObjectResponseHandler(File file, String bucketName, String objectKey) {
        this(file, false);
        this.mBucketName = bucketName;
        this.mObjectKey = objectKey;
    }

    public abstract void onTaskProgress(double progress);

    public abstract void onSuccess(GetObjectRequest request, GetObjectResult result);

    public abstract void onTaskCancel();

    public abstract void onFailure(GetObjectRequest request, Ks3ClientException clientException, Ks3ServiceException serviceException);

    @Override
    public final void onFailure(Ks3HttpRequest request, Ks3ClientException clientException, Ks3ServiceException serviceException) {
        this.onFailure((GetObjectRequest) request, clientException, serviceException);
    }

    @Override
    public void onProgress(long bytesWritten, long totalSize) {
        double progress = Double.valueOf(totalSize > 0 ? bytesWritten * 1.0D / totalSize * 100.0D : -1.0D);
        onTaskProgress(progress);
    }

    @Override
    public void onRetry(int retryNo) {
    }

    @Override
    public void onSuccess(Ks3HttpRequest request, int statusCode, Headers responseHeaders, byte[] response) {
        GetObjectResult result = parse(statusCode, responseHeaders);
        result.setStatusCode(statusCode);
        result.setHeaders(ResponseUtils.parseResponseHeaders(responseHeaders));
        this.onSuccess((GetObjectRequest) request, result);
    }


    @Override
    public void onCancel() {
        this.onTaskCancel();
    }

    private GetObjectResult parse(int statusCode, Headers responseHeaders) {
        GetObjectResult result = new GetObjectResult();
        ObjectMetadata metaData = new ObjectMetadata();

        result.getObject().setBucketName(mBucketName);
        result.getObject().setKey(mObjectKey);
        if (statusCode == 200 || statusCode == 206) {
            Headers header = responseHeaders;
            for (int i = 0; i < header.size(); i++) {
                String name = header.name(i);
                String value = header.value(i);
                if (HttpHeaders.XKssWebsiteRedirectLocation.toString().equalsIgnoreCase(name)) {
                    result.getObject().setRedirectLocation(value);
                } else if (name.startsWith(ObjectMetadata.userMetaPrefix)) {
                    metaData.addOrEditUserMeta(name, value);
                } else {
                    if (name.equalsIgnoreCase(HttpHeaders.LastModified.toString())) {

                        metaData.addOrEditMeta(ObjectMetadata.Meta.LastModified, value);

                    } else if (name.equalsIgnoreCase(HttpHeaders.ETag.toString())) {

                        metaData.addOrEditMeta(ObjectMetadata.Meta.Etag, value.replace("\"", ""));
                        metaData.addOrEditMeta(ObjectMetadata.Meta.ContentMD5,
                                Md5Utils.ETag2MD5(value));

                    } else if (name.equalsIgnoreCase(ObjectMetadata.Meta.CacheControl.toString())) {

                        metaData.addOrEditMeta(ObjectMetadata.Meta.CacheControl, value);

                    } else if (name.equalsIgnoreCase(ObjectMetadata.Meta.ContentDisposition
                            .toString())) {

                        metaData.addOrEditMeta(ObjectMetadata.Meta.ContentDisposition, value);

                    } else if (name
                            .equalsIgnoreCase(ObjectMetadata.Meta.ContentEncoding.toString())) {

                        metaData.addOrEditMeta(ObjectMetadata.Meta.ContentEncoding, value);

                    } else if (name.equalsIgnoreCase(ObjectMetadata.Meta.ContentLength.toString())) {

                        metaData.addOrEditMeta(ObjectMetadata.Meta.ContentLength, value);

                    } else if (name.equalsIgnoreCase(ObjectMetadata.Meta.ContentType.toString())) {

                        metaData.addOrEditMeta(ObjectMetadata.Meta.ContentType, value);

                    } else if (name.equalsIgnoreCase(ObjectMetadata.Meta.Expires.toString())) {

                        metaData.setExpires(value);

                    } else if (name.equalsIgnoreCase(HttpHeaders.XKssObjectTagCount.toString())) {
                        metaData.addOrEditMeta(ObjectMetadata.Meta.XKssObjectTagCount, value);
                    }
                }
            }
            result.getObject().setObjectMetadata(metaData);
        } else if (statusCode == 304) {
            result.setIfModified(false);
        } else if (statusCode == 412) {
            result.setIfPreconditionSuccess(false);
        }
        return result;
    }

}
